﻿import spade
from LBCrawlerAgent import LBCrawlerAgent, RespondLoadQuery
from CrawlerAgent import MyPeriodicBehaviour
import random


_show_function_calls = True


  ##################################################################
  ## SenderLBCrawlerAgent                                         ##
  ##################################################################

class SenderLBCrawlerAgent(LBCrawlerAgent): # agent z consistent hashing i sender init LB
  class SendLoadQuery(MyPeriodicBehaviour):
    def __init__(self, period, timestart=0):#, max_agents=1):
      MyPeriodicBehaviour.__init__(self, period, timestart)
##      self.max_agents_to_consult = max_agents

    def _onTick(self):
      if _show_function_calls:
        print '\t+SendLoadQuery'
      self.myAgent.received_responses = 0
      self.myAgent.lowest_agent = None
      if self.myAgent.slb_agents == []:
        return
##      print self.myAgent.slb_agents
      msg = spade.ACLMessage.ACLMessage()
      msg.setPerformative('query-ref')
      msg.setOntology(self.myAgent.service_name)
      msg.setContent('')
      aname = self.myAgent.getName()
      sent_list = [aname]
##      for i in xrange(min(self.max_agents_to_consult, len(self.myAgent.slb_agents))):
      for i in xrange(len(self.myAgent.slb_agents)):
        anum = len(self.myAgent.slb_agents)
        while aname in sent_list:
          aname = self.myAgent.slb_agents[random.randint(0, anum-1)]
        sent_list.append(aname)
        receiver = spade.AID.aid(name=aname, addresses=['xmpp://' + aname])
        msg.addReceiver(receiver)
##        print self.myAgent.getName(), '->', aname, msg
      print '\t\tSTART'
      self.myAgent.add_stat_sent_msgs()
      self.myAgent.send(msg)
      if _show_function_calls:
        print '\t-SendLoadQuery'
  ##################################################################
  class ReceiveLoadAndSendLBToLowest(spade.Behaviour.Behaviour):
    def send_to_lowest(self):
      my_qsize, my_upt = map(float, [self.myAgent.url_queue.qsize(), self.myAgent.avg_urls_per_tick])
      other_qsize, other_upt = self.myAgent.lowest_params
      diff2 = int(-(other_qsize * my_upt - my_qsize * other_upt) / (other_upt + my_upt)) # ilosc urli, ktore agent wysle
##      print my_qsize/my_upt, other_qsize/other_upt
      if diff2 > 0:
        self.myAgent.send_urls(diff2, self.myAgent.lowest_agent)
      print '\t\tKONIEC'

    def _process(self):
      msg = None
      msg = self._receive()
      if msg:
        self.myAgent.add_stat_rcvd_msgs()
        if _show_function_calls:
          print '\t+ReceiveLoadAndSendLBToLowest'
        rcvd_qsize, rcvd_upt = map(float, msg.getContent().split('#'))
        sender = msg.getSender()
        rcvd_load = rcvd_qsize / rcvd_upt
        if rcvd_load < self.myAgent.lowest_load or not self.myAgent.lowest_agent:
          self.myAgent.lowest_agent = sender
          self.myAgent.lowest_load = rcvd_load
          self.myAgent.lowest_params = (rcvd_qsize, rcvd_upt)
        self.myAgent.received_responses += 1
        if self.myAgent.received_responses >= len(self.myAgent.slb_agents) and self.myAgent.lowest_agent:
          self.send_to_lowest()
        if _show_function_calls:
          print '\t-ReceiveLoadAndSendLBToLowest'
  ##################################################################
  def set_slb_agents(self, agents):
    self.slb_agents = agents
    print '#slb', self.slb_agents
  ##################################################################
  def _setup(self):
    self.received_responses = 0
    self.lowest_agent = None
    self.lowest_load = 0
    self.lowest_params = (0, 0)
    self.slb_agents = []

    self.service_name = 'sender_lb'
    self.transfer_service_name = self.service_name + '_url_transfer'
    self.set_lb_agents = self.set_slb_agents

    b = self.SendLoadQuery(self.behav_period, self.lb_timestart)
    self.addBehaviour(b)

    template = spade.Behaviour.ACLTemplate()
    template.setPerformative('query-ref')
    template.setOntology(self.service_name)
    mt1 = spade.Behaviour.MessageTemplate(template)
    b = RespondLoadQuery()
    self.addBehaviour(b, mt1)

    template = spade.Behaviour.ACLTemplate()
    template.setPerformative('inform')
    template.setOntology(self.service_name)
    mt = spade.Behaviour.MessageTemplate(template)
    b = self.ReceiveLoadAndSendLBToLowest()
    self.addBehaviour(b, mt)

    self.add_service(self.service_name)

    LBCrawlerAgent._setup(self)
